﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Xml.Linq;

using umbraco.cms.businesslogic.datatype;
using umbraco.interfaces;
using umbraco.cms.businesslogic.web;
using umbraco.DataLayer;
using umbraco.BusinessLogic;
using umbraco.cms.businesslogic.propertytype;
using umbraco.cms.businesslogic;
using umbraco.cms.businesslogic.media;
using umbraco;
using System.Xml.XPath;

namespace DigibizAdvancedMediaPicker
{
    public class DAMP_DataType : AbstractDataEditor
    {
        private IData _data;
        private DAMP_DataEditor _control = new DAMP_DataEditor();
        private DAMP_PrevalueEditor _preValueEditor;

        #region Properties

        public bool StoreAsXML
        {
            get
            {
                return ((DAMP_PrevalueEditor)PrevalueEditor).SaveValue == "fullMedia";
            }
        }

        protected static ISqlHelper SqlHelper
        {
            get 
            { 
                return Application.SqlHelper; 
            }
        }

        #endregion

        public DAMP_DataType()
            : base()
        {
            this.RenderControl = this._control;

            this._control.Load += new EventHandler(m_control_Load);

            this.DataEditorControl.OnSave += new AbstractDataEditorControl.SaveEventHandler(DataEditorControl_OnSave);
        }

        private void m_control_Load(object sender, EventArgs e)
        {
            //Get some values which we need multiple times.
            bool selectMultipleNodesValue = ((DAMP_PrevalueEditor)PrevalueEditor).SelectMultipleNodesValue;
            int minimumNodesValue = ((DAMP_PrevalueEditor)PrevalueEditor).MinimumNodesValue;
            int maximumNodesValue = ((DAMP_PrevalueEditor)PrevalueEditor).MaximumNodesValue;

            //Set the default values for the minimum and maximum nodes text.
            string minimumNodesText = string.Format("You need to select a minimum of {0} media {1}", minimumNodesValue, minimumNodesValue == 1 ? "item" : "items");
            string maximumNodesText = string.Format("You need to select a maximum of {0} media {1}", maximumNodesValue, maximumNodesValue == 1 ? "item" : "items");
            string mandatoryText = selectMultipleNodesValue ? "You need to select a minimum of 1 media item" : "You need to select a media item";

            //Get the propertyId which we need to get the current PropertyType.
            int propertyId = StoreAsXML ? ((DAMP_Data)this.Data).PropertyId : ((DefaultData)this.Data).PropertyId;

            bool mandatory = false;

            //Check if the propertyId is not 0. If it is this DataType is probably used in a custom section and no PropertyType is available.
            if (propertyId != 0)
            {
                try
                {
                    //Get the current PropertyType because we need some property data.
                    PropertyType propertyType = new PropertyType(SqlHelper.ExecuteScalar<int>("select propertytypeid from cmsPropertyData where id = @id", SqlHelper.CreateParameter("@id", propertyId)));

                    //Store the mandatory field.
                    mandatory = propertyType.Mandatory;

                    //Get the name of the tab.
                    string tabCaption = SqlHelper.ExecuteScalar<string>("Select text from " + (umbraco.GlobalSettings.VersionMajor > 4 ? "cmsPropertyTypeGroup" : "cmsTab") + " where id = " + propertyType.TabId);

                    if(string.IsNullOrEmpty(tabCaption))
                    {
                        //If no tab is found this means it's on the default (Generic Properties) tab.
                        tabCaption = "Properties";
                    }

                    //Set the minimum and maximum nodes text and the mandatory text now that we have a property name and tab.
                    minimumNodesText = string.Format("The {0} field in the {1} tab needs a minimum of {2} media {3}", propertyType.Name, tabCaption, minimumNodesValue, minimumNodesValue == 1 ? "item" : "items");
                    maximumNodesText = string.Format("The {0} field in the {1} tab needs a maximum of {2} media {3}", propertyType.Name, tabCaption, maximumNodesValue, maximumNodesValue == 1 ? "item" : "items");
                    mandatoryText = selectMultipleNodesValue ? string.Format("The {0} field in the {1} tab needs a minimum of 1 media item", propertyType.Name, tabCaption) : string.Format("The {0} field in the {1} tab needs a media item", propertyType.Name, tabCaption);
                }
                catch (Exception ex)
                {
                    DAMP_Helper.LogException(ex);
                }
            }

            //Get the current user.
            User currentUser = User.GetCurrent();

            int startNodeId = 0;
            if (((DAMP_PrevalueEditor)PrevalueEditor).IgnoreStartNodeAdminValue && currentUser.UserType.Alias == "admin")
            {
                //If the current user is an admin and IgnoreStartNodeAdminValue is true the start node will be the default start node the user has rights to.
                startNodeId = currentUser.StartMediaId;
            }
            else
            {
                if (((DAMP_PrevalueEditor)PrevalueEditor).SelectStartPickerValue == "picker")
                {
                    //If the Media Picker is used use the selected start node as the start node.
                    startNodeId = ((DAMP_PrevalueEditor)PrevalueEditor).StartNodeIdValue;
                }
                else
                {
                    //Define the start node by the XPath.
                    //For more info on why this is done this way see: http://our.umbraco.org/forum/developers/api-questions/19043-Speed-if-I-use-libraryGetMedia-recursive-on-top-media-node.

                    var xpathValue = ((DAMP_PrevalueEditor)PrevalueEditor).StartNodeXpathValue;

                    Document document = new Document(Convert.ToInt32(HttpContext.Current.Request.QueryString["id"]));

                    //First check if the xpath field might be a property on the current node.
                    if (document.getProperty(xpathValue) != null && document.getProperty(xpathValue).Value != null)
                    {
                        int startId;
                        if (int.TryParse(document.getProperty(xpathValue).Value.ToString(), out startId))
                        {
                            //If the property exists and contains an id use that id as the start node and skip the xpath part.
                            startNodeId = startId;
                        }
                        else
                        {
                            //If no id is found use the user his user section start node.
                            startNodeId = currentUser.StartMediaId;
                        }
                    }
                    else
                    {
                        //Performance could be slow if the entire media tree xml needs to be created.

                        //Create an empty xmlDocument.
                        XDocument xmlDocument = new XDocument(
                                new XElement("Media")
                            );

                        if (currentUser.StartMediaId == -1)
                        {
                            //If the currentUser has no start node in the user section loop through all the top media nodes.
                            using (IRecordsReader dr = SqlHelper.ExecuteReader("Select id from umbracoNode where nodeObjectType = @type And parentId = -1 order by sortOrder",
                                SqlHelper.CreateParameter("@type", Media._objectType)))
                            {
                                while (dr.Read())
                                {
                                    //Get the hierarchical xml from each topnode and add it to the xmlDocument.
                                    xmlDocument.Root.Add(XElement.Parse(library.GetMedia(dr.GetInt("id"), true).Current.OuterXml));
                                }
                            }
                        }
                        else
                        {
                            //Get the hierarchical xml from the user his start node in the user section and add it to the xmlDocument.
                            xmlDocument.Root.Add(XElement.Parse(library.GetMedia(currentUser.StartMediaId, true).Current.OuterXml));
                        }

                        //Use an XPath on the xml.
                        XPathNavigator xPathNavigator = xmlDocument.CreateNavigator();
                        XPathNodeIterator xPathNodeIterator = xPathNavigator.Select(xpathValue);
                        xPathNodeIterator.MoveNext();

                        int id;
                        if (int.TryParse(xPathNodeIterator.Current.Evaluate("string(@id)").ToString(), out id))
                        {
                            //If an id is found set it as the start node.
                            startNodeId = id;
                        }
                        else
                        {
                            //If no id is found use the user his user section start node.
                            startNodeId = currentUser.StartMediaId;
                        }
                    }
                }
            }
            
            
            //Set prevalues.
            _control.SaveValue = ((DAMP_PrevalueEditor)PrevalueEditor).SaveValue;
            _control.AllowedExtensionsValue = ((DAMP_PrevalueEditor)PrevalueEditor).AllowedExtensionValue;
            _control.AllowedSelectableMediaTypesValue = ((DAMP_PrevalueEditor)PrevalueEditor).AllowedSelectableMediaTypesValue;
            _control.AllowedCreateableMediaTypesValue = ((DAMP_PrevalueEditor)PrevalueEditor).AllowedCreateableMediaTypesValue;
            _control.DefaultMediaTypeValue = ((DAMP_PrevalueEditor)PrevalueEditor).DefaultMediaTypeValue;
            _control.HideCreateValue = ((DAMP_PrevalueEditor)PrevalueEditor).HideCreateValue;
            _control.StartNodeIdValue = startNodeId;
            _control.SelectMultipleNodesValue = selectMultipleNodesValue;
            _control.MinimumNodesValue = minimumNodesValue;
            _control.MaximumNodesValue = maximumNodesValue;
            _control.CropPropertyAliasValue = ((DAMP_PrevalueEditor)PrevalueEditor).CropPropertyAliasValue;
            _control.CropNameValue = ((DAMP_PrevalueEditor)PrevalueEditor).CropNameValue;
            _control.ThumbnailWidthValue = ((DAMP_PrevalueEditor)PrevalueEditor).ThumbnailWidthValue;
            _control.ThumbnailHeightValue = ((DAMP_PrevalueEditor)PrevalueEditor).ThumbnailHeightValue;
            _control.HideEditValue = ((DAMP_PrevalueEditor)PrevalueEditor).HideEditValue;
            _control.HideOpenValue = ((DAMP_PrevalueEditor)PrevalueEditor).HideOpenValue;
            _control.HidePixlrValue = ((DAMP_PrevalueEditor)PrevalueEditor).HidePixlrValue;
            _control.EnableSearch = ((DAMP_PrevalueEditor)PrevalueEditor).EnableSearch;
            _control.EnableSearchAutoSuggest = ((DAMP_PrevalueEditor)PrevalueEditor).EnableSearchAutoSuggest;
            _control.SearchMethod = ((DAMP_PrevalueEditor)PrevalueEditor).SearchMethod;

            //Set other properties.
            _control.Mandatory = mandatory;
            _control.CheckValidation = true;
            _control.MinimumNodesText = minimumNodesText;
            _control.MaximumNodesText = maximumNodesText;
            _control.MandatoryText = mandatoryText;
            _control.DataTypeDefinitionId = this.DataTypeDefinitionId;

            //Set saved value.
            _control.Value = this.Data.Value;
        }

        /// <summary>
        /// Gets the id of the data-type.
        /// </summary>
        /// <value>The id of the data-type.</value>
        public override Guid Id
        {
            get
            {
                return new Guid("ef94c406-9e83-4058-a780-0375624ba7ca");
            }
        }

        /// <summary>
        /// Gets the name of the data type.
        /// </summary>
        /// <value>The name of the data type.</value>
        public override string DataTypeName
        {
            get
            {
                return "Digibiz Advanced Media Picker";
            }
        }

        public override IData Data
        {
            get
            {
                if (this._data == null)
                {
                    if (!StoreAsXML)
                    {
                        this._data = new DefaultData(this);
                    }
                    else
                    {
                        this._data = new DAMP_Data(this);
                    }
                }

                return this._data;
            }

        }

        /// <summary>
        /// Gets the prevalue editor.
        /// </summary>
        /// <value>The prevalue editor.</value>
        public override IDataPrevalue PrevalueEditor
        {
            get
            {
                if (this._preValueEditor == null)
                {
                    this._preValueEditor = new DAMP_PrevalueEditor(this);
                }

                return this._preValueEditor;
            }
        }

        /// <summary>
        /// Handle the saving event, need to give data to Umbraco.
        /// </summary>
        /// <param name="e"></param>
        private void DataEditorControl_OnSave(EventArgs e)
        {
            object val = _control.Value;

            if (val != null)
            {
                this.Data.Value = val.ToString();
            }
            else
            {
                this.Data.Value = null;
            }
        }
    }
}